package com.reus.statement;

import com.reus.reflect.ClazzWrapper;
import com.reus.reflect.ObjectWrapper;
import com.reus.reflect.ObjectWrapperFactory;
import com.reus.util.TypeUtil;

import java.lang.reflect.Constructor;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * description: ResultSet结果处理器，执行之后返回的json对象，转为java对象的过程
 * copyright: Copyright (c) 2018-2021
 * company: iSysCore Tech. Co., Ltd.
 *
 * @author liuxq@isyscore.com
 * @version 1.0
 * @date 2021-10-19 19:20:19
 */
public class ResultSetHandle {

    /**
     * 转换的目标类型
     */
    Class<?> typeReturn;

    /**
     * 待转换的ResultSet
     */
    ResultSet resultSet;

    Boolean hasSet;

    public ResultSetHandle(Class<?> typeReturn, ResultSet resultSet) {
        this.resultSet = resultSet;
        this.typeReturn = typeReturn;
    }

    /**
     * ResultSet处理方法，目前仅支持String,int,Float,不支持属性是集合类 todo
     */
    public <T> List<T> handle() throws Exception {

        List<T> res = new ArrayList<>(resultSet.getRow());
        Object object;
        ObjectWrapper objectWrapper = null;
        Set<ClazzWrapper.FiledExpand> filedExpands = null;
        // 返回类型若不是基本数据类型
        if (!TypeUtil.isBaseType(typeReturn)) {
            // 生成对象
            object = generateObj(typeReturn);
            // 将对象封装成包装类
            objectWrapper = ObjectWrapperFactory.getInstance(object);

            /** 获取对象属性 */
            filedExpands = objectWrapper.getMapperFiledExpands();
        }

        while (resultSet.next()) {
            /** 若返回是基础数据类型，则直接将结果放入List中并返回 */
            if (String.class.equals(typeReturn)) {
                String val = resultSet.getString(1);
                if (val != null) {
                    res.add((T) val);
                }
            } else if (Integer.class.equals(typeReturn) || int.class.equals(typeReturn)) {
                Integer val = resultSet.getInt(1);
                if (val != null) {
                    res.add((T) val);
                }
            } else if (Float.class.equals(typeReturn) || float.class.equals(typeReturn)) {
                Float val = resultSet.getFloat(1);
                if (val != null) {
                    res.add((T) val);
                }
            } else { // 若返回的是对象（如User这种）
                // 查找对象属性，一个个注入
                for (ClazzWrapper.FiledExpand filedExpand : filedExpands) {
                    // 如果对象属性是String类型，例如User.name是String类型
                    if (String.class.equals(filedExpand.getType())) {
                        // resultSet中获取该属性
                        String val = resultSet.getString(filedExpand.getPropertiesName());
                        if (val != null) {
                            // 填充到对象包装类中
                            objectWrapper.setVal(filedExpand.getPropertiesName(), val);
                        }
                    } else if (Integer.class.equals(filedExpand.getType()) || int.class.equals(filedExpand.getType())) {
                        Integer val = resultSet.getInt(filedExpand.getPropertiesName());
                        if (val != null) {
                            objectWrapper.setVal(filedExpand.getPropertiesName(), val);
                        }
                    } else if (Float.class.equals(filedExpand.getType()) || float.class.equals(filedExpand.getType())) {
                        Float val = resultSet.getFloat(filedExpand.getPropertiesName());
                        if (val != null) {
                            objectWrapper.setVal(filedExpand.getPropertiesName(), val);
                        }
                    } else {
                        continue;
                    }
                }
                // 后续将对象包装类转为真实对象，放入List中并返回。对象包装类见代码10
                res.add((T) objectWrapper.getRealObject());
            }
        }
        return res;
    }

    // 根据类型，根据反射，实例化对象
    private Object generateObj(Class<?> clazz) throws Exception {
        Constructor[] constructors = clazz.getConstructors();
        Constructor usedConstructor = null;
        // 获取无参构造器，若对象没有无参构造方法，则失败
        for (Constructor constructor : constructors) {
            if (constructor.getParameterCount() == 0) {
                usedConstructor = constructor;
                break;
            }
        }
        if (constructors == null) {
            throw new RuntimeException(typeReturn + " is not empty constructor");
        }
        // 利用反射生成实例
        return usedConstructor.newInstance();
    }
}
